package k8s

import (
	"bytes"
	"context"
	"fmt"
	"strings"
	"time"

	"gitee.com/hexug/go-tools/common/validate"
	"gitee.com/hexug/go-tools/logger"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/util/json"
	"k8s.io/apimachinery/pkg/util/yaml"
	"sigs.k8s.io/kustomize/api/krusty"
	"sigs.k8s.io/kustomize/api/resmap"
	"sigs.k8s.io/kustomize/api/types"
	"sigs.k8s.io/kustomize/kyaml/filesys"
	yaml1 "sigs.k8s.io/kustomize/kyaml/yaml"
)

func (g *implK8s) CreateOrUpdateConfigMapFromYaml(c context.Context, req *CreateOrUpdateConfigMapFromYamlRequest) (*corev1.ConfigMap, error) {
	start := time.Now()
	defer func() {
		logger.L().Infof("elapsed K8SAPI_CreateOrUpdateConfigMapFromYaml:%v", time.Since(start))
	}()
	if err := validate.V().Struct(req); err != nil {
		logger.L().Errorf("参数校验失败:%v", err)
		return nil, fmt.Errorf("参数校验失败:%v", err)
	}
	configMap := &corev1.ConfigMap{}
	reader := bytes.NewReader([]byte(req.YamlStr))
	decoder := yaml.NewYAMLOrJSONDecoder(reader, 4096)
	if err := decoder.Decode(configMap); err != nil {
		logger.L().Errorf("解析 YAML 失败: %v", err)
		return nil, fmt.Errorf("解析 YAML 失败: %v", err)
	}
	configMap.Namespace = g.Namespace
	reqGetCm := NewGetConfigMapRequest(configMap.Name)
	cm, err := g.GetConfigMap(c, reqGetCm)
	if err != nil {
		logger.L().Infof("未找到 configmap %s: %v ", configMap.Name, err)
		return g.Clientset.CoreV1().ConfigMaps(g.Namespace).Create(c, configMap, metav1.CreateOptions{})
	}
	logger.L().Infof("已找到 configmap %s,准备更新！", configMap.Name)
	cm, err = g.Clientset.CoreV1().ConfigMaps(g.Namespace).Update(c, configMap, metav1.UpdateOptions{})
	if err == nil {
		logger.L().Info("update configmap success")
		return cm, nil
	}

	logger.L().Errorf("更新 configmap %s 失败: %v ", configMap.Name, err)
	return nil, err
}

func (g *implK8s) GetConfigMap(c context.Context, req *GetConfigMapRequest) (*corev1.ConfigMap, error) {
	start := time.Now()
	defer func() {
		logger.L().Infof("ConfigMap %s elapsed K8SAPI_GetConfigMap:%v", req.Name, time.Since(start))
	}()

	// 1. 参数校验
	if err := validate.V().Struct(req); err != nil {
		logger.L().Errorf("参数校验失败:%v", err)
		return nil, fmt.Errorf("参数校验失败:%v", err)
	}
	return g.Clientset.CoreV1().ConfigMaps(g.Namespace).Get(c, req.Name, metav1.GetOptions{})
}

func (g *implK8s) CreateOrUpdateConfigMapFromJson(c context.Context, req *CreateOrUpdateConfigMapFromJsonRequest) (*corev1.ConfigMap, error) {
	start := time.Now()
	defer func() {
		logger.L().Infof("elapsed K8SAPI_CreateOrUpdateConfigMapFromJson:%v", time.Since(start))
	}()
	if err := validate.V().Struct(req); err != nil {
		logger.L().Errorf("参数校验失败:%v", err)
		return nil, fmt.Errorf("参数校验失败:%v", err)
	}
	configMap := &corev1.ConfigMap{}
	if err := json.Unmarshal([]byte(req.ConfigMapJson), configMap); err != nil {
		logger.L().Errorf("Failed to unmarshal ConfigMap JSON: %v", err)
		return nil, fmt.Errorf("failed to unmarshal ConfigMap JSON: %v", err)
	}
	configMap.Namespace = g.Namespace
	reqGetCm := NewGetConfigMapRequest(configMap.Name)
	cm, err := g.GetConfigMap(c, reqGetCm)
	if err == nil {
		logger.L().Infof("已找到 configmap %s，将要更新configmap", configMap.Name)
		cm, err = g.Clientset.CoreV1().ConfigMaps(g.Namespace).Update(c, configMap, metav1.UpdateOptions{})
		if err != nil {
			logger.L().Errorf("Failed to update ConfigMap: %v", err)
			return nil, fmt.Errorf("failed to update ConfigMap: %v", err)
		}
		return cm, nil
	} else {
		logger.L().Warnf("未找到 configmap %s, 准备创建configmap：%s", configMap.Name, err.Error())
		return g.Clientset.CoreV1().ConfigMaps(g.Namespace).Create(c, configMap, metav1.CreateOptions{})
	}

}

func (g *implK8s) useKustomizeFromFilesToConfigMap(req *CreateOrUpdateConfigMapFromFilesRequest) (resmap.ResMap, error) {
	// 1. 创建内存文件系统，用于存放虚拟 kustomization.yaml 和内存文件
	fs := filesys.MakeFsInMemory()

	// 2. 构造 Kustomization 对象（等价于在 YAML 中定义 configMapGenerator）
	//    - Resources: 空，表示没有引用额外的 YAML 资源
	//    - ConfigMapGenerator: 配置生成 ConfigMap 的规则
	//    - GeneratorOptions.DisableNameSuffixHash: 禁止 Kustomize 自动加 hash 后缀
	k := &types.Kustomization{
		Resources: []string{},
		ConfigMapGenerator: []types.ConfigMapArgs{
			{
				GeneratorArgs: types.GeneratorArgs{
					Name: req.ConfigMap, // 基础 ConfigMap 名称
					KvPairSources: types.KvPairSources{
						// 使用 LiteralSources 将内存中的 "文件名=内容" 塞进 data
						LiteralSources: []string{},
					},
				},
			},
		},
		GeneratorOptions: &types.GeneratorOptions{
			DisableNameSuffixHash: true,
		},
	}

	// 3. 将上传的文件内容转换成 literal，并加入 ConfigMapGenerator
	for filename, data := range req.FileMap {
		kv := fmt.Sprintf("%s=%s", filename, string(data))
		k.ConfigMapGenerator[0].LiteralSources = append(k.ConfigMapGenerator[0].LiteralSources, kv)
	}

	// 4. 序列化 Kustomization 对象为 YAML，写入内存文件系统
	yml, err := yaml1.Marshal(k)
	if err != nil {
		logger.L().Errorf("Failed to marshal Kustomization: %v", err)
		return nil, err
	}
	if err := fs.WriteFile("kustomization.yaml", yml); err != nil {
		logger.L().Errorf("Failed to write kustomization.yaml: %v", err)
		return nil, err
	}

	// 5. 用 krusty 编译内存文件系统，生成 resMap
	kustomizer := krusty.MakeKustomizer(krusty.MakeDefaultOptions())
	return kustomizer.Run(fs, ".")
}

func (g *implK8s) CreateOrUpdateConfigMapFromFiles(ctx context.Context, req *CreateOrUpdateConfigMapFromFilesRequest) (*corev1.ConfigMap, error) {
	start := time.Now()
	defer func() {
		logger.L().Infof("ConfigMap %s elapsed K8SAPI_CreateOrUpdateConfigMapFromFiles:%v", req.ConfigMap, time.Since(start))
	}()

	// 1. 参数校验
	if err := validate.V().Struct(req); err != nil {
		logger.L().Errorf("参数校验失败:%v", err)
		return nil, fmt.Errorf("参数校验失败:%v", err)
	}

	// 2. 使用 kustomize 运行内存文件系统，生成 resMap
	resMap, err := g.useKustomizeFromFilesToConfigMap(req)
	if err != nil {
		logger.L().Errorf("运行 kustomize 错误:%v", err)
		return nil, fmt.Errorf("运行 kustomize 失败: %v", err)
	}
	cmClient := g.CoreV1().ConfigMaps(g.Namespace)
	// 3. 遍历 resMap 中的资源，只处理 ConfigMap 类型
	for _, r := range resMap.Resources() {
		if r.GetKind() != "ConfigMap" {
			continue
		}

		// 5. 获取底层 map[string]interface{} 对象
		objMap, err := r.Map()
		if err != nil {
			logger.L().Errorf("获取 ConfigMap 对象失败：%s", err.Error())
			return nil, fmt.Errorf("获取 ConfigMap 对象失败: %v", err)
		}

		// 6. 将 map 转换成 typed ConfigMap 对象
		var cm corev1.ConfigMap
		if err := runtime.DefaultUnstructuredConverter.FromUnstructured(objMap, &cm); err != nil {
			logger.L().Errorf("转换 ConfigMap 失败：%s", err.Error())
			return nil, fmt.Errorf("转换 ConfigMap 失败: %v", err)
		}

		// 7. 强制覆盖 namespace
		cm.Namespace = g.Namespace

		// 8. 判断 ConfigMap 是否已存在
		reqGetConfigMap := NewGetConfigMapRequest(cm.Name)
		_, err = g.GetConfigMap(ctx, reqGetConfigMap)
		if err != nil {
			// 不存在 → 创建
			confmp, err := cmClient.Create(context.Background(), &cm, metav1.CreateOptions{})
			if err != nil {
				logger.L().Errorf("创建 ConfigMap 错误:%v", err)
				return nil, fmt.Errorf("创建 ConfigMap 失败: %v", err)
			}
			logger.L().Infof("ConfigMap %s 创建成功", cm.Name)

			return confmp, nil

		} else {
			// 已存在 → 更新
			confmp, err := cmClient.Update(context.Background(), &cm, metav1.UpdateOptions{})
			if err != nil {
				logger.L().Errorf("更新 ConfigMap 错误:%v", err)
				return nil, fmt.Errorf("更新 ConfigMap 失败: %v", err)
			}
			logger.L().Infof("ConfigMap %s 更新成功", cm.Name)
			return confmp, nil
		}
	}

	// 10. 如果 resMap 中没有 ConfigMap，返回错误
	return nil, fmt.Errorf("未找到 ConfigMap")
}

func (g *implK8s) ListConfigMap(c context.Context, req *ListConfigMapRequest) (*corev1.ConfigMapList, error) {
	start := time.Now()
	defer func() {
		logger.L().Infof("elapsed K8SAPI_ListConfigMap:%v", time.Since(start))
	}()
	if err := validate.V().Struct(req); err != nil {
		logger.L().Errorf("参数校验失败:%v", err)
		return nil, fmt.Errorf("参数校验失败:%v", err)
	}
	if len(req.Labels) == 0 {
		return g.CoreV1().ConfigMaps(g.Namespace).List(c, metav1.ListOptions{})
	}
	// 构建标签选择器字符串
	var selectorParts []string
	for key, value := range req.Labels {
		selectorParts = append(selectorParts, fmt.Sprintf("%s=%s", key, value))
	}
	if req.UseAnd {
		labelSelector := strings.Join(selectorParts, ",")
		return g.CoreV1().ConfigMaps(g.Namespace).List(c, metav1.ListOptions{
			LabelSelector: labelSelector,
		})
	}
	ls := &corev1.ConfigMapList{}
	for _, value := range selectorParts {
		res, err := g.CoreV1().ConfigMaps(g.Namespace).List(c, metav1.ListOptions{
			LabelSelector: value,
		})
		if err != nil {
			logger.L().Errorf("查找标签 %s 失败:%v", value, err)
			return nil, err
		}
		for _, cm := range res.Items {
			flag := false
			for _, v := range ls.Items {
				if cm.Name == v.Name {
					flag = true
					break
				}
			}
			if !flag {
				ls.Items = append(ls.Items, cm)
			}
		}
	}
	return ls, nil
}

func (g *implK8s) DeleteConfigMap(c context.Context, req *DeleteConfigMapRequest) (*corev1.ConfigMap, error) {
	start := time.Now()
	defer func() {
		logger.L().Infof("elapsed K8SAPI_DeleteConfigMap:%v", time.Since(start))
	}()
	if err := validate.V().Struct(req); err != nil {
		logger.L().Errorf("参数校验失败:%v", err)
		return nil, fmt.Errorf("参数校验失败:%v", err)
	}
	reqGetCm := NewGetConfigMapRequest(req.Name)
	cm, err := g.GetConfigMap(c, reqGetCm)
	if err != nil {
		logger.L().Errorf("未找到 %s configmap", req.Name)
		return nil, err
	}
	deletePolicy := metav1.DeletePropagationBackground
	deleteOptions := metav1.DeleteOptions{
		PropagationPolicy: &deletePolicy,
	}

	return cm, g.CoreV1().ConfigMaps(g.Namespace).Delete(c, req.Name, deleteOptions)
}
